package com.wsd.bookkeeping.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsd.bookkeeping.entity.Record;
import com.wsd.bookkeeping.entity.query.*;
import com.wsd.bookkeeping.mapper.RecordMapper;
import com.wsd.bookkeeping.service.RecordService;
import com.wsd.bookkeeping.vo.*;
import com.wsd.common.constant.AccountConstant;
import com.wsd.common.constant.CommonConstant;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class RecordServiceImpl extends ServiceImpl<RecordMapper, Record> implements RecordService {

    @Value("${query.page-size}")
    private Integer pageSize;

    @Resource
    private RecordMapper recordMapper;

    @Override
    public Map<String, Object> queryByRecordId(Integer id) {
        return baseMapper.queryByRecordId(id);
    }

    @Override
    public List<Map<String, Object>> queryPage(RecordQuery recordQuery) {

        if (!Objects.isNull(recordQuery.getDate()) && !recordQuery.getDate().isEmpty()) {
            String date = recordQuery.getDate();  // 获取查询日期
            recordQuery.setStartDate(date + "01");
            recordQuery.setEndDate(date + "31");
        }

        recordQuery.setStartNumber((recordQuery.getCurPage() - 1) * pageSize);
        recordQuery.setPageSize(pageSize);
        return recordMapper.queryPage(recordQuery);
    }

    @Override
    // todo 添加分页查询
    public List<Map<String, Object>> queryAmountByDate(Integer bookId, String date) {
        return baseMapper.queryAmountByDate(bookId, date);
    }

    @Override
    public List<IncomeListEntityVO> queryIncomeList(IncomeListQuery incomeListQuery) {
        incomeListQuery.setPageSize(pageSize);
        incomeListQuery.setStartNumber(incomeListQuery.getCurPage(), pageSize);
        return baseMapper.queryIncomeList(incomeListQuery);
    }

    @Override
    public List<UserIncomeListVO> queryUserIncomeList(IncomeListQuery incomeListQuery, Integer userId) {
        incomeListQuery.setPageSize(pageSize);
        incomeListQuery.setStartNumber(incomeListQuery.getCurPage(), pageSize);
        return baseMapper.queryUserIncomeList(incomeListQuery, userId);
    }

    @Override
    public List<OutcomeListEntityVO> queryOutcomeList(OutcomeListQuery outcomeListQuery) {
        outcomeListQuery.setPageSize(pageSize);
        outcomeListQuery.setStartNumber(outcomeListQuery.getCurPage(), pageSize);
        return baseMapper.queryOutcomeList(outcomeListQuery);
    }

    @Override
    public List<UserOutcomeListVO> queryUserOutcomeList(OutcomeListQuery outcomeListQuery, Integer userId) {
        outcomeListQuery.setPageSize(pageSize);
        outcomeListQuery.setStartNumber(outcomeListQuery.getCurPage(), pageSize);
        return baseMapper.queryUserOutcomeList(outcomeListQuery, userId);
    }

    @Override
    public Map<String, Map<Integer, BigDecimal>> queryAccountSummaryByBookId(Integer bookId) throws InterruptedException {

        Map<String, Map<Integer, BigDecimal>> res = new HashMap<>(2);
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.submit(() -> {
            Map<Integer, BigDecimal> partMap = this.queryAccountSummaryByType(bookId, AccountConstant.ACCOUNT_INCOME);
            res.put("income", partMap);
        });

        executorService.submit(() -> {
            Map<Integer, BigDecimal> partMap = this.queryAccountSummaryByType(bookId, AccountConstant.ACCOUNT_OUTCOME);
            res.put("outcome", partMap);
        });

        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);

        return res;
    }

    @Override
    public Map<String, Map<String, BigDecimal>> queryAccountClassificationRankByBookId(Integer bookId) throws InterruptedException {
        Map<String, Map<String, BigDecimal>> res = new HashMap<>(2);
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.submit(() -> {
            Map<String, BigDecimal> dataMap = this.queryAccountClassificationByBookId(bookId, AccountConstant.ACCOUNT_INCOME, CommonConstant.YEAR_RANGE);
            res.put("income", dataMap);
        });

        executorService.submit(() -> {
            Map<String, BigDecimal> dataMap = this.queryAccountClassificationByBookId(bookId, AccountConstant.ACCOUNT_OUTCOME, CommonConstant.YEAR_RANGE);
            res.put("outcome", dataMap);
        });

        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);

        return res;
    }

    @Override
    public int deleteByBookId(Integer bookId) {
        return baseMapper.deleteByBookId(bookId);
    }


    /**
     * 图标展示-折线图-查询月收入支出总额
     * @param bookId
     * @param type
     * @return
     */
    private Map<Integer, BigDecimal> queryAccountSummaryByType(Integer bookId, String type) {
        AccountSummaryQuery accountSummaryQuery = new AccountSummaryQuery();
        accountSummaryQuery.setType(type);
        accountSummaryQuery.setBookId(bookId);

        Map<Integer, BigDecimal> dataMap = new HashMap<>(12);
        List<AccountSummaryVO> accountSummaryVOS = baseMapper.querySummaryByType(accountSummaryQuery.init());

        Map<Integer, BigDecimal> collect = accountSummaryVOS.stream().collect(Collectors.toMap(item -> Integer.valueOf(item.getMonth()), AccountSummaryVO::getTotal));
        dataMap.putAll(collect);

        for (int i = 0; i < 12; i++) {
            if (!dataMap.containsKey(i)) {
                dataMap.put(i, BigDecimal.ZERO);
            }
        }

        return dataMap;
    }

    /**
     * 图表展示-扇形图-查询年/月 收入|支出排行
     * @param bookId
     * @param type
     * @param range
     * @return
     */
    private Map<String, BigDecimal> queryAccountClassificationByBookId(Integer bookId, String type, Integer range) {
        AccountClassificationQuery accountClassificationQuery = new AccountClassificationQuery();
        accountClassificationQuery.setBookId(bookId);
        accountClassificationQuery.setType(type);
        accountClassificationQuery.setRange(range);

        List<AccountClassificationRankVO> accountClassificationRankVOS = baseMapper.queryClassificationRankListByType(accountClassificationQuery);
        return accountClassificationRankVOS.stream().collect(Collectors.toMap(AccountClassificationRankVO::getStyleName, AccountClassificationRankVO::getTotal));
    }
}
